/*
	Copyright (c) 2010 <copyright holders>
	This source code is licensed under The MIT License,
	see the file LICENSE for details.
	*/

#ifndef SIMNETLOGIC_HPP
#define SIMNETLOGIC_HPP

#include <list>
#include <map>

#include "ForwardDecls.hpp"
#include "Net.hpp"
#include "Spatial.hpp"

namespace spelprog2 {
namespace sim {

namespace net_logic {


class WorldNetListener : public net::NetMessageListener {
protected:
    WorldManager & worldMan_;

    bool getPlayerId(const net::Net & net, net::UserId userId, Int & playerId);
public:
    WorldNetListener(WorldManager & worldMan) : net::NetMessageListener(), worldMan_(worldMan) {}
    virtual ~WorldNetListener() { }
};


/**
    Handles the incoming messages, and puts them in a queue (update queue
    for messages from server, requests from clients). Also delivers messages to WorldManager
    in the processX functions.
    */
class MessageQueuer : public WorldNetListener {
    HIDE_EVIL_CONSTRUCTORS(MessageQueuer);

    typedef std::pair<MessagePtr, net::NetMessageInfo> MessageQueueEntry;
    typedef std::list<MessageQueueEntry> MessageQueue;

    MessageQueue queue_;
public:
    typedef boost::shared_ptr<MessageQueuer> Pointer;

    MessageQueuer(WorldManager & worldMan);
    void onMessage(MessagePtr msg, const net::NetMessageInfo & info);

    void clear() { queue_.clear(); }
    void processUpdates();
    void processRequests();
    bool hasUpdateMessage() const;
    void loadReplayFrames(file::MessageInputFile & replayFile, net::Net & net);
};


/**
    Deals with update logic. It handles FrameUpdate messages tp track lagging clients.
    It calls simUpdate() in associated WorldManager when it's time to do a simulation update.
    */
class HandleFrameUpdate : public WorldNetListener {
    HIDE_EVIL_CONSTRUCTORS(HandleFrameUpdate);

    typedef std::map<net::UserId, unsigned> ReachedFrames;

    net::Net & net_;
    ReachedFrames reachedFrames_;
    unsigned frameCounter_;
    float netUpdateTime_;
    unsigned simUpdateInNetCount_;
    MessageQueuer::Pointer queuer_;

    bool maySimUpdate() const;
    bool mayNetUpdate() const;
    bool hasLaggers() const;
public:
    HandleFrameUpdate(WorldManager & worldMan, net::Net & net);
    void onMessage(MessagePtr msg, const net::NetMessageInfo & info);

    void reset();
    void run(float timeDelta);

    MessageQueuer::Pointer getMessageQueuer() { return queuer_; }
};


struct HandleMoveSquad : public WorldNetListener {
    HandleMoveSquad(WorldManager & worldMan) : WorldNetListener(worldMan) { }
    void onMessage(MessagePtr msg, const net::NetMessageInfo & info);
};


struct HandleChangeFormation : public WorldNetListener {
    HandleChangeFormation(WorldManager & worldMan) : WorldNetListener(worldMan) { }
    void onMessage(MessagePtr msg, const net::NetMessageInfo & info);
};


struct HandleStopSquad : public WorldNetListener {
    HandleStopSquad(WorldManager & worldMan) : WorldNetListener(worldMan) { }
    void onMessage(MessagePtr msg, const net::NetMessageInfo & info);
};


}; //net_logic
}; //sim
}; //spelprog2

#endif //SIMNETLOGIC_HPP